#include "pch.h"

#include "iosystem/binaryreader.h"



namespace IO
{
	RE_ImplementClass('BINR', IO::BinaryReader, IO::StreamReader);



	///
	BinaryReader::BinaryReader():
	m_enableMapping(false),
		m_isMapped(false),
		m_mapCursor(0),
		m_mapEnd(0)
	{

	}


	///
	BinaryReader::~BinaryReader()
	{
		if(this->IsOpen())
		{
			this->Close();
		}
	}


	///
	bool BinaryReader::Open()
	{
		if(StreamReader::Open())
		{
			if(this->m_enableMapping && this->m_stream->CanMap())
			{
				this->m_isMapped = true;

				this->m_mapCursor = (unsigned char*)this->m_stream->Map();

				this->m_mapEnd = this->m_mapCursor + this->m_stream->GetSize();
			}
			else
			{
				this->m_isMapped = false;

				this->m_mapCursor = 0;

				this->m_mapEnd = 0;
			}

			return true;
		}

		return false;
	}


	///
	void BinaryReader::Close()
	{
		StreamReader::Close();

		this->m_isMapped = false;

		this->m_mapCursor = 0;

		this->m_mapEnd = 0;
	}



	///
	char BinaryReader::ReadChar()
	{
		if(this->m_isMapped)
		{
			return *this->m_mapCursor++;
		}
		else
		{
			char c;

			this->m_stream->Read(&c, sizeof(c));

			return c;
		}
	}


	///
	uchar BinaryReader::ReadUChar()
	{
		if(this->m_isMapped)
		{
			return *this->m_mapCursor++;
		}
		else
		{
			uchar c;

			this->m_stream->Read(&c, sizeof(c));

			return c;
		}
	}


	///
	short BinaryReader::ReadShort()
	{
		short val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<short>(val);
	}


	///
	ushort BinaryReader::ReadUShort()
	{
		ushort val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<ushort>(val);
	}


	///
	int BinaryReader::ReadInt()
	{
		int val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<int>(val);
	}


	///
	uint BinaryReader::ReadUInt()
	{
		uint val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<uint>(val);
	}


	///
	float BinaryReader::ReadFloat()
	{
		float val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<float>(val);
	}


	///
	double BinaryReader::ReadDouble()
	{
		double val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		return this->m_byteOrder.Convert<double>(val);
	}


	///
	bool BinaryReader::ReadBool()
	{
		bool val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val,sizeof(val));
		}

		return val;
	}


	///
	Helper::String BinaryReader::ReadString()
	{
		if(this->m_isMapped)
		{
			ushort length = this->ReadUShort();

			Helper::String str;

			if(length > 0)
			{
				str.Reserve(length + 1);

				char * buf = (char*)str.GetAsCharPtr();

				Memory::MemoryManager::Copy(this->m_mapCursor, buf, length);

				this->m_mapCursor += length;

				buf[length] = 0;
			}

			return str;
		}
		else
		{
			ushort length = this->ReadUShort();

			Helper::String str;

			if(length > 0)
			{
				str.Reserve(length + 1);

				char * buf = (char*)str.GetAsCharPtr();

				this->m_stream->Read((void*)buf, length);

				buf[length] = 0;
			}

			return str;
		}
	}


	///
	Math::float2 BinaryReader::ReadFloat2()
	{
		Math::float2 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()));

		return val;
	}


	///
	Math::float4 BinaryReader::ReadFloat4()
	{
		Math::float4 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		this->m_byteOrder.ConvertInPlace<Math::float4>(val);

		return val;
	}


	///
	Math::point2 BinaryReader::ReadPoint2()
	{
		Math::point2 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()));

		return val;
	}


	///
	Math::point4 BinaryReader::ReadPoint4()
	{
		Math::point4 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()),
				this->m_byteOrder.Convert<float>(val.getz()));

		return val;
	}


	///
	Math::plane BinaryReader::ReadPlane()
	{
		Math::plane val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getA()),
				this->m_byteOrder.Convert<float>(val.getB()),
				this->m_byteOrder.Convert<float>(val.getC()),
				this->m_byteOrder.Convert<float>(val.getD()));

		return val;
	}


	///
	Math::vector2 BinaryReader::ReadVector2()
	{
		Math::vector2 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()));

		return val;
	}


	///
	Math::vector3 BinaryReader::ReadVector3()
	{
		Math::vector3 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()),
				this->m_byteOrder.Convert<float>(val.getz()));

		return val;
	}


	///
	Math::vector4 BinaryReader::ReadVector4()
	{
		Math::vector4 val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		val.set(this->m_byteOrder.Convert<float>(val.getx()),
				this->m_byteOrder.Convert<float>(val.gety()),
				this->m_byteOrder.Convert<float>(val.getz()),
				this->m_byteOrder.Convert<float>(val.getw()));

		return val;
	}


	///
	Math::matrix BinaryReader::ReadMatrix()
	{
		Math::matrix val;

		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, &val, sizeof(val));

			this->m_mapCursor += sizeof(val);
		}
		else
		{
			this->m_stream->Read(&val, sizeof(val));
		}

		this->m_byteOrder.ConvertInPlace<Math::matrix>(val);

		return val;
	}


	///
	void BinaryReader::ReadRawData(void *ptr, tSize bytes)
	{
		if(this->m_isMapped)
		{
			Memory::MemoryManager::Copy(this->m_mapCursor, ptr, bytes);

			this->m_mapCursor += bytes;
		}
		else
		{
			this->m_stream->Read(ptr, bytes);
		}
	}






	///
	void BinaryReader::SetMemoryMappingEnabled(bool b)
	{
		this->m_enableMapping = b;
	}


	///
	bool BinaryReader::IsMemoryMappingEnabled() const 
	{
		return this->m_enableMapping;
	}


	///
	void BinaryReader::SetStreamEndianess(System::ByteOrder::Type order)
	{
		this->m_byteOrder.SetFromEndianess(order);
	}


	///
	System::ByteOrder::Type BinaryReader::GetStreamEndianess() const
	{
		return this->m_byteOrder.GetFromEndianess();
	}

}